/*
 * =====================================================================================
 * Copyright (C) 2024 Ingenic Semiconductor Co.,Ltd
 * All Rights Reserved
 *
 * Filename     : pwm.c
 * Author       : Keven <keven.ywhan@ingenic.com>
 * Created      : 2024/07/09 14:54
 * Description  :
 *
 * =====================================================================================
 */

#include <common/reg_pwm.h>
#include <pwm.h>
#include <printk.h>

static void pwm_clk_config(uint32_t chn, uint32_t prescale)
{
	uint32_t value = 0;

	if(chn < 8) {
		value = readl(PWM_CCFG0) & ~(0xf << (chn *4));
		value |= prescale << (chn * 4);
		writel(value, PWM_CCFG0);
	} else {
		value = readl(PWM_CCFG1) & ~(0xf << (chn *4));
		value |= prescale << (chn * 4);
		writel(value, PWM_CCFG1);
	}
}

static void pwm_set_init_level(uint32_t chn, uint32_t level)
{
	uint32_t value;

	value = readl(PWM_LVL);
	if(level)
		value |= 1 << chn;
	else
		value &= ~(1 << chn);
	writel(value, PWM_LVL);
}
static void pwm_set_finish_level(uint32_t chn, uint32_t level)
{
	uint32_t value;

	value = readl(PWM_LVL);
	if(level)
		value |= 1 << (chn + 16);
	else
		value &= ~(1 << (chn + 16));
	writel(value, PWM_LVL);
}

static void pwm_waveform_high(uint32_t chn, uint16_t high_num)
{
	int32_t value = 0;
	value = readl(PWM_WCFG(chn));
	value &= ~(0xffff << 16);
	value |= high_num << 16;
	writel(value, PWM_WCFG(chn));
}

static void pwm_waveform_low(uint32_t chn, uint16_t low_num)
{
	int32_t value = 0;
	value = readl(PWM_WCFG(chn));
	value &= ~(0xffff);
	value |= low_num;
	writel(value, PWM_WCFG(chn));
}


int32_t pwm_channel_config(uint32_t chn, struct pwm_config *config)
{
	pwm_clk_config(chn, 0x1);

	pwm_set_init_level(chn, config->init_level);

	pwm_waveform_high(chn, config->duty_ns);
	pwm_waveform_low(chn, config->period_ns - config->duty_ns);

	pwm_set_finish_level(chn, 0);

	/* pwm io output enabld */
	writel(0x1<<chn, PWM_OEN);

	writel(0x1<<chn, PWM_UPDATE);

	return 0;
}

int32_t pwm_channel_updata_config(uint32_t chn, struct pwm_config *config)
{
	pwm_channel_config(chn, config);
	while(readl(PWM_BUSYR) & 0x1<<chn);

	return 0;
}


int32_t pwm_channel_enable(uint32_t chn)
{
	writel(0x1<<chn, PWM_ENS);

	return 0;
}

int32_t pwm_channel_disable(uint32_t chn)
{
	writel(0x1<<chn, PWM_ENC);

	return 0;
}
